using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using System.Timers;

namespace Armory
{
	class Combat
	{
		private bool inCombat = false;
		private System.Timers.Timer totalCombat;
		private System.Timers.Timer globalCooldown;
		private System.Timers.Timer myETimer;
		private System.Timers.Timer myMHTimer;
		private System.Timers.Timer myOHTimer;

		private double MHTime = 0;
		private double OHTime = 0;
		private double ETime = 0;

		private int aggressionRank = 0;
		private int lethalityRank = 0;

		private Character myChar;
		private double combatTime;
		private DateTime combatStartTime;
		private int timeModifier = 10;
		//private int timeModifier = 1000;

		private List<string>  mHHits = new List<string>();

		public List<string> MHHits
		{
			get { return mHHits; }
			set { mHHits = value; }
		}

		private List<string> oHHits = new List<string>();

		public List<string> OHHits
		{
			get { return oHHits; }
			set { mHHits = value; }
		}

		private List<string> sHits = new List<string>();

		public List<string> SHits
		{
			get { return sHits; }
			set { sHits = value; }
		}

		private List<string> energyTicks = new List<string>();

		public List<string> EnergyTicks
		{
			get { return energyTicks; }
			set { energyTicks = value; }
		}

		private double dps;

		public double Dps
		{
			get { return dps; }
			set { dps = value; }
		}
	
		public Combat(Character myChar, TimeSpan combatTime)
		{
			this.myChar = myChar;
			this.combatTime = combatTime.TotalSeconds;

			//HARDCODE
			aggressionRank = 3;
			lethalityRank = 5;
		}

		public void Start()
		{
			this.inCombat = true;

			castSpecialAttack();

			totalCombat = new System.Timers.Timer();
			totalCombat.Elapsed += new ElapsedEventHandler(totalCombatTimeEvent);
			totalCombat.AutoReset = false;
			totalCombat.Interval = combatTime * timeModifier;

			globalCooldown = new System.Timers.Timer();
			globalCooldown.Elapsed += new ElapsedEventHandler(globalCooldownTimeEvent);
			globalCooldown.AutoReset = false;
			globalCooldown.Interval = 1 * timeModifier;

			myETimer = new System.Timers.Timer();
			myETimer.Elapsed += new ElapsedEventHandler(ETimeEvent);
			myETimer.AutoReset = false;
			myETimer.Interval = 2 * timeModifier;

			myMHTimer = new System.Timers.Timer();
			myMHTimer.Elapsed += new ElapsedEventHandler(MHTimeEvent);
			myMHTimer.AutoReset = false;
			myMHTimer.Interval = Double.Parse(myChar.MeleeStats.MainHandWeapon.Speed.ToString()) * timeModifier;

			myOHTimer = new System.Timers.Timer();
			myOHTimer.Elapsed += new ElapsedEventHandler(OHTimeEvent);
			myOHTimer.AutoReset = false;
			myOHTimer.Interval = Double.Parse(myChar.MeleeStats.OffHandWeapon.Speed.ToString()) * timeModifier;

			totalCombat.Start();
			globalCooldown.Start();
			myMHTimer.Start();
			myOHTimer.Start();
			myETimer.Start();

			while(inCombat)
			{
				Thread.Sleep(100);
			}

			Thread.Sleep(500);
		}

		private double doSpecialHit(int cost)
		{
			return 0;
		}

		public void totalCombatTimeEvent(object source, ElapsedEventArgs e)
		{
			this.inCombat = false;
		}

		public void globalCooldownTimeEvent(object source, ElapsedEventArgs e)
		{
			castSpecialAttack();
			this.globalCooldown.Start();
		}

		public void MHTimeEvent(object source, ElapsedEventArgs e)
		{
			MHTime += myMHTimer.Interval / timeModifier;

			doMHWhite();

			DateTime MHTimeEventFired = DateTime.Now;
			TimeSpan test = MHTimeEventFired.Subtract(this.combatStartTime);

			if(MHTime + (myMHTimer.Interval / timeModifier) < combatTime)
			{
				this.myMHTimer.Start();
			}
		}

		public void OHTimeEvent(object source, ElapsedEventArgs e)
		{
			OHTime += myOHTimer.Interval / timeModifier;

			doOHWhite();

			DateTime OHTimeEventFired = DateTime.Now;
			TimeSpan test = OHTimeEventFired.Subtract(this.combatStartTime);

			if(OHTime + (myOHTimer.Interval / timeModifier) < combatTime)
			{
				this.myOHTimer.Start();
			}
		}

		public void ETimeEvent(object source, ElapsedEventArgs e)
		{
			ETime += myETimer.Interval / timeModifier;

			int sEnergy = this.myChar.CurrentEnergy;
			int mEnergy = this.myChar.MaxEnergy;
			int tEnergy = 100;

			if(sEnergy < mEnergy)
			{
				tEnergy = sEnergy + 20;

				if(tEnergy > mEnergy)
				{
					tEnergy = mEnergy;
				}
			}
			this.myChar.CurrentEnergy = tEnergy;
			energyTicks.Add(sEnergy + " -> " + tEnergy);

			if(ETime + (myETimer.Interval / timeModifier) < combatTime)
			{
				this.myETimer.Start();
			}
		}

		private void doMHWhite()
		{
			double white = getWeaponDamage(this.myChar.MeleeStats.MainHandWeapon);

			if(isCrit(Double.Parse(this.myChar.MeleeStats.CritChance)))
			{
				white = white * 2;
			}

			mHHits.Add(white.ToString());
		}

		private void doOHWhite()
		{
			double white = getWeaponDamage(this.myChar.MeleeStats.OffHandWeapon);

			if(isCrit(Double.Parse(this.myChar.MeleeStats.CritChance)))
			{
				white = white * 2;
			}

			oHHits.Add(white.ToString());
		}

		private void castSpecialAttack()
		{
			if(myChar.CurrentEnergy > 39)
			{
				myChar.CurrentEnergy -= 40;
				castSinisterStrike();
			}
		}

		private void castSinisterStrike()
		{
			double aggression = 1 + (0.02 * aggressionRank);
			double lethality = 0.06 * lethalityRank;
			//double modifier = (double.Parse(myChar.MeleeStats.AttackPower) / 14) * 2.4;
			double modifier = 0;
			double rSinisterStrike = (getWeaponDamage(myChar.MeleeStats.MainHandWeapon) + modifier + 98) * aggression;

			if(isCrit(Double.Parse(this.myChar.MeleeStats.CritChance)))
			{
				rSinisterStrike = rSinisterStrike * (2 + lethality);
			}
			sHits.Add(rSinisterStrike.ToString());
		}

		private double getWeaponDamage(MeleeWeaponStats mws)
		{
			double damageRange = Int16.Parse(mws.RangeMax) - Int16.Parse(mws.RangeMin);
			Random rint = new Random(DateTime.Now.Millisecond);

			Thread.Sleep(10);

			double randomDamage = (rint.NextDouble() * damageRange) + Int16.Parse(mws.RangeMin);
			return randomDamage;
		}

		private bool isCrit(double critChance)
		{
			Random rint = new Random(DateTime.Now.Millisecond);
			if(rint.NextDouble() * 100 < critChance)
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		public void CalculateDPS()
		{
			double allHits = 0;
			foreach(string mHHit in this.mHHits)
			{
				allHits += double.Parse(mHHit);
			}

			foreach(string oHHit in oHHits)
			{
				allHits += double.Parse(oHHit);
			}

			foreach(string sHit in sHits)
			{
				allHits += double.Parse(sHit);
			}

			this.dps = allHits / (int)combatTime;
		}

	}
}
